/******************************************************************************
 * Filename : uc_socket.c
 * Created  : 2009-8-8 by franco.yin
 * Description -
 *
 ******************************************************************************/

#ifdef __cplusplus
extern "C" {
#endif

#include "uc_socket.h"

int
ucsock_socket(int domain, int type, int protocol)
{
	return socket(domain, type, protocol);
}

int
ucsock_socketpair(int domain, int type, int protocol, int sockvec[2])
{
	return socketpair(domain, type, protocol, sockvec);
}

int
ucsock_bind(int fd, SA_IN *addr)
{
	int addrlen = sizeof (SA_IN);
	return bind(fd, (SA *) addr, addrlen);
}

int
ucsock_connect(int sockfd, const SA *serv_addr, socklen_t addrlen)
{
	int ret = 0;

	while (1) {
		ret = connect(sockfd, serv_addr, addrlen);
		if ((ret < 0) && (errno == EINTR || errno == EAGAIN)) {
			continue;
		}
		return ret;
	}
}

int
ucsock_accept(int fd)
{
	int ret = 0;

	while (1) {
		ret = accept(fd, NULL, NULL);
		if (ret < 0) {
			if (errno == EINTR || errno == EAGAIN) {
				continue;
			}
//			uc_err( "accept() errno(%d)\n", errno);
			return ret;
		}
		return ret;
	}
}

int
ucsock_recv(int fd, char *buf, int len)
{
	int ret = 0;

	while (1) {
		ret = recv(fd, buf, len, 0);
		if (ret < 0) {
			if (errno == EINTR || errno == EAGAIN) {
				continue;
			}
//			uc_err("recv() errno(%d)\n", errno);
			return ret;
		}
		return ret;
	}
}

int
ucsock_recv_nonblock(int fd, char *buf, int len, int *block)
{
	int ret = 0;

	*block = 0;
	while (1) {
		ret = recv(fd, buf, len, MSG_DONTWAIT);
		if (ret < 0) {
			if (errno == EINTR) {
				continue;
			} else if (errno == EAGAIN || errno == EWOULDBLOCK) {
				*block = 1;
			}
			//uc_err("recv(%d) [%d:%s] p[%p]\n", ret, errno, strerror(errno), buf);
			return ret;
		}
		return ret;
	}
}

int
ucsock_recvfrom(int fd, char *buf, int len, SA_IN *addr, socklen_t *addr_len)
{
	int ret = 0;

	while (1) {
		if (addr != NULL) {
			*addr_len = sizeof(SA_IN);
			ret = recvfrom(fd, buf, len, 0, (SA *)addr, addr_len);
		} else {
			ret = recvfrom(fd, buf, len, 0, NULL, NULL);
		}
		if (ret < 0) {
			if (errno == EINTR || errno == EAGAIN) {
				continue;
			}
//			uc_err("recvfrom() errno(%d)\n", errno);
			return ret;
		}
		return ret;
	}
}

int
ucsock_recvfrom_nonblock(int fd, char *buf, int len, SA_IN *addr, socklen_t *addr_len, int *block)
{
	//for udp
	int ret = 0;

	while (1) {
		if (addr != NULL) {
			*addr_len = sizeof(SA_IN);
			ret = recvfrom(fd, buf, len, MSG_DONTWAIT, (SA *)addr, addr_len);
		} else {
			ret = recvfrom(fd, buf, len, MSG_DONTWAIT, NULL, NULL);
		}
		if (ret < 0) {
			if(errno == EINTR) {
				continue;
			} else if (errno == EAGAIN || errno == EWOULDBLOCK) {
				*block = 1;
			}
//			uc_err("recvfrom() errno(%d)\n", errno);
			return ret;
		}
		return ret;
	}
}

int
ucsock_recvn(int fd, char *buf, int len, int timout_ms)
{
	int nleft = 0;
	int nread = 0;
	char *ptr = NULL;
	int err_flag = 0;
	UC_S64 start_time = 0;
	UC_S64 now_time = 0;

	if(timout_ms <= 0) {
		timout_ms = UC_SOCKET_RECV_TIMEOUT;
	}
	ptr = buf;
	nleft = len;
	while (nleft > 0) {
		if ((nread = recv(fd, ptr, nleft, 0)) < 0) {
			if (errno == EINTR || errno == EAGAIN) {
				nread = 0;
				if(err_flag <= 0) {
					err_flag = 1;
					start_time = uctime_uptime_msec();
				} else {
					now_time = uctime_uptime_msec();
					if (now_time - start_time >= timout_ms || now_time < start_time) {
						uc_err("fd[%d] recv error, ret[%d] errno[%d:%s]\n", fd, nread, errno, strerror(errno));
						return ERROR;
					}
				}
			} else {
//				uc_err("recv2() errno(%d)\n", errno);
				return ERROR;
			}
		} else if (nread == 0) {
			break;
		} else {
			err_flag = 0;
		}
		nleft -= nread;
		ptr += nread;
	}
	return (len - nleft);
}

int
ucsock_recv_msg(int fd, ucmsg_s *pMsg, int len, int timout_ms)
{
	if(ucsock_recvn(fd, (char *)pMsg, sizeof(ucmsg_s), timout_ms) <= 0) {
		return ERROR;
	} else {
		ucmsg_ntoh(pMsg);
		if(pMsg->len > len - sizeof(ucmsg_s)) {
			uc_err("ucsock_recv_msg too long[%d - %d]\n", pMsg->len, len);
			return ERROR;
		}

		if(pMsg->len > 0) {
			if(ucsock_recvn(fd, (char *)pMsg->data, pMsg->len, timout_ms) <= 0) {
				return ERROR;
			}
		}

		return pMsg->len + sizeof(ucmsg_s);
	}
}

int
ucsock_send(int fd, char *buf, int len)
{
	int ret = 0;

	while (1) {
		ret = send(fd, buf, len, 0);
		if (ret < 0) {
			if (errno == EINTR || errno == EAGAIN) {
				continue;
			}
//			uc_err( "send() errno(%d)\n", errno);
			return ret;
		}
		return ret;
	}
}

int
ucsock_send_nonblock(int fd, char *buf, int len, int *block)
{
	int ret = 0;

	*block = 0;
	while (1) {
		ret = send(fd, buf, len, MSG_DONTWAIT);
		if (ret < 0) {
			if (errno == EINTR) {
				continue;
			} else if (errno == EAGAIN || errno == EWOULDBLOCK) {
				*block = 1;
			}
//			uc_err("send() errno(%d)\n", errno);
			return ret;
		}
		return ret;
	}
}

int
ucsock_sendto_nonblock(int fd, char *buf, int len, SA_IN *addr, int *block)
{
	//for udp
	int ret = 0;

	*block = 0;
	while (1) {
		ret = sendto(fd, buf, len, MSG_DONTWAIT, (SA *)addr, (socklen_t)(sizeof(SA_IN)));
		if (ret < 0) {
			if (errno == EINTR) {
				continue;
			} else if (errno == EAGAIN || errno == EWOULDBLOCK) {
				*block = 1;
			}
//			uc_err( "sendto() errno(%d)\n", errno);
			return ret;
		}
		return ret;
	}
}

int
ucsock_sendto(int fd, char *buf, int len, SA_IN *addr)
{
	int ret = 0;

	while (1) {
		ret = sendto(fd, buf, len, 0, (SA *)addr, (socklen_t)(sizeof(SA_IN)));
		if (ret < 0) {
			if (errno == EINTR || errno == EAGAIN) {
				continue;
			}
//			uc_err( "sendto() errno(%d)\n", errno);
			return ret;
		}
		return ret;
	}
}

int
ucsock_sendn(int fd, char *buf, int len, int timout_ms)
{
	int nleft = 0;
	int nwritten = 0;
	char *ptr = NULL;
	int err_flag = 0;
	UC_S64 start_time;
	UC_S64 now_time;

	if(timout_ms <= 0) {
		timout_ms = UC_SOCKET_SEND_TIMEOUT;
	}
	ptr = buf;
	nleft = len;
	while (nleft > 0) {
		if ((nwritten = send(fd, ptr, nleft, 0)) < 0) {
			if (errno == EINTR || errno == EAGAIN) {
				nwritten = 0;
				if(err_flag <= 0) {
					err_flag = 1;
					start_time = uctime_uptime_msec();
				} else {
					now_time = uctime_uptime_msec();
					if (now_time - start_time >= timout_ms || now_time < start_time) {
						uc_err("fd[%d] send error, ret[%d] errno[%d:%s]\n", fd, nwritten, errno, strerror(errno));
						return ERROR;
					}
				}
			} else {
//				uc_err("send2() errno(%d)\n", errno);
				return ERROR;
			}
		} else {
			err_flag = 0;
		}
		nleft -= nwritten;
		ptr += nwritten;
	}
	return len;
}

char *
ucsock_inet_ntoa(UC_U32 ipaddr)
{
	struct in_addr addr;

	addr.s_addr = htonl(ipaddr);
	return inet_ntoa(addr);
}

char *
ucsock_inet_addr_ntoa_r(struct in_addr ina, char *buf)
{
	UC_U8 *ucp = (UC_U8 *) &ina;

	sprintf(buf, "%d.%d.%d.%d", ucp[0] & 0xff, ucp[1] & 0xff, ucp[2] & 0xff, ucp[3] & 0xff);
	return buf;
}

char *
ucsock_inet_ntoa_r(UC_U32 ipaddr, char *buf)
{
	struct in_addr addr;

	addr.s_addr = htonl(ipaddr);
	return ucsock_inet_addr_ntoa_r(addr, buf);
}

UC_U32
ucsock_inet_aton(char *ipstr)
{
	struct in_addr addr;

	inet_aton(ipstr, &addr);
	return ntohl(addr.s_addr);
}

int
ucsock_get_address_by_name(char *ifname, UC_U32 *address)
{
    int fd = -1;
    struct ifreq ifr;
    int ret = 1;

    fd = socket(PF_INET, SOCK_DGRAM, 0);
    if ( fd < 0 ) {
		return ERROR;
	}

    memset(&ifr, 0, sizeof(ifr));
    strncpy( ifr.ifr_name, ifname, IFNAMSIZ);
    ret = ioctl(fd, SIOCGIFADDR, &ifr, sizeof(ifr));
    if (ret < 0) {
        close(fd);
		return ERROR;
    }
    *address = ((SA_IN *)(&ifr.ifr_addr))->sin_addr.s_addr;

    return OK;
}

int
ucsock_server(char *ipstr, int port)
{
	int fd = 0;
	int ret = 0, on = 0;
	SA_IN addr;

	fd = ucsock_socket(AF_INET, SOCK_STREAM, 0);
	if (fd <= 0) {
		uc_err( "socket(%d)\n", port);
		return ERROR;
	}

	on = 1;
	ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on));
	if (ret != OK) {
		uc_close(fd);
		uc_err( "setsockopt(%d)\n", port);
		return ERROR;
	}

/*
	on = 1;
	if (setsockopt(fd, IPPROTO_TCP, TCP_DEFER_ACCEPT, (void *) &on, sizeof(on)) < 0) {
		uc_err( "setsockopt(TCP_DEFER_ACCEPT) failed: %d\n", errno);
		uc_close(fd);
		return ERROR;
	}
*/

	memset(&addr, 0, sizeof (addr));
	addr.sin_family = AF_INET;
	if (ipstr != NULL) {
		addr.sin_addr.s_addr = inet_addr(ipstr);
	}
	addr.sin_port = htons(port);

	ret = ucsock_bind(fd, &addr);
	if (ret != OK) {
		uc_close(fd);
		uc_err( "bind(%d)\n", port);
		return ERROR;
	}

	/* Notice: should be get tcp_max_syn_backlog by sysctl */
	ret = listen(fd, 256);
	if (ret != OK) {
		uc_close(fd);
		uc_err( "listen(%d)\n", port);
		return ERROR;
	}

	return fd;
}

int
ucsock_server_udp(char *ipstr, int port)
{
	int fd = 0;
	int ret = 0, on = 0;
	SA_IN addr;

	fd = ucsock_socket(AF_INET, SOCK_DGRAM, 0);
	if (fd <= 0) {
		uc_err( "socket(%d)\n", port);
		return ERROR;
	}

	on = 1;
	ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on));
	if (ret != OK) {
		uc_close(fd);
		uc_err( "setsockopt(%d)\n", port);
		return ERROR;
	}

	memset(&addr, 0, sizeof (addr));
	addr.sin_family = AF_INET;
	if (ipstr != NULL) {
		addr.sin_addr.s_addr = inet_addr(ipstr);
	}
	addr.sin_port = htons(port);

	ret = ucsock_bind(fd, &addr);
	if (ret != OK) {
		uc_close(fd);
		uc_err( "bind(%d)\n", port);
		return ERROR;
	}

	return fd;
}

int
ucsock_server_udp_group(char *group, char *ipstr, int port)
{
	int fd = 0;
	int ret = 0, on = 0;
	struct ip_mreq mreq;
	SA_IN addr;

	fd = ucsock_socket(AF_INET, SOCK_DGRAM, 0);
	if (fd <= 0) {
		uc_err( "socket(%d)\n", port);
		return ERROR;
	}

	on = 1;
	ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on));
	if (ret != OK) {
		uc_close(fd);
		uc_err( "setsockopt(%d)\n", port);
		return ERROR;
	}

	memset(&addr, 0, sizeof (addr));
	addr.sin_family = AF_INET;
	inet_aton(group, &addr.sin_addr);
	addr.sin_port = htons(port);

	ret = ucsock_bind(fd, &addr);
	if (ret != OK) {
		uc_close(fd);
		uc_err( "bind(%d)\n", port);
		return ERROR;
	}

	memset(&mreq, 0, sizeof(struct ip_mreq));
	inet_aton(group, &mreq.imr_multiaddr);
	if (ipstr != NULL) {
		inet_aton(ipstr, &(mreq.imr_interface) );
	}
	if(setsockopt(fd, SOL_IP, IP_ADD_MEMBERSHIP, &mreq,sizeof(mreq)) < 0){
		uc_close(fd);
		uc_err( "set membership error[%d:%s]\n", errno, strerror(errno));
		return ERROR;
	}

	return fd;
}

int
ucsock_client(char *ipstr, int port, int type)
{
	int fd = 0, ret = 0;
	SA_IN addr;

	fd = ucsock_socket(AF_INET, type, 0);
	if (fd <= 0) {
		uc_err( "socket error\n");
		return -1;
	}

	if(type == SOCK_DGRAM) {
		return fd;
	}

	memset(&addr, 0, sizeof (SA_IN));
	addr.sin_family = AF_INET;
	addr.sin_port = htons(port);
	addr.sin_addr.s_addr = inet_addr(ipstr);

	ret = ucsock_connect(fd, (SA *) &addr, sizeof (addr));
	if (ret < 0) {
		uc_close(fd);
		uc_err( "connect,[%s:%d] error\n", ipstr, port);
		return -1;
	}

	return fd;
}

int
ucsock_connect_nonblock(char *ipstr, int port, int type, char *dev)
{
	int fd, ret, flags;
	SA_IN addr;
	char ip[UC_BUF_LEN];
	char netmask[UC_BUF_LEN];

	fd = ucsock_socket(AF_INET, type, 0);
	if (fd <= 0) {
		return -1;
	}

	if(dev != NULL && strlen(dev) > 0) {
		if(ucsock_fd_bind_to_device(fd, dev) < 0) {
			uc_close(fd);
			uc_err("creat client to[%s:%d] bind device error\n", ipstr, port);
			return -1;
		}
	}

	if(type == SOCK_DGRAM && dev != NULL) {
		ucnet_if_get_net_addr(dev, ip, netmask);

		memset(&addr, 0, sizeof (SA_IN));
		addr.sin_family = AF_INET;
		addr.sin_port = htons(0);
		addr.sin_addr.s_addr = inet_addr(ip);

		if (ucsock_bind(fd, &addr) != 0) {
			uc_err("UDP client bind dev[%s] error !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n", dev);
		}

		return fd;
	}

	memset(&addr, 0, sizeof (SA_IN));
	addr.sin_family = AF_INET;
	addr.sin_port = htons(port);
	addr.sin_addr.s_addr = inet_addr(ipstr);

	flags = fcntl(fd, F_GETFL);
	fcntl(fd, F_SETFL, flags | O_NONBLOCK);

	ret = ucsock_connect(fd, (SA *) &addr, sizeof (addr));
	if (ret < 0) {
		if (errno != EINPROGRESS) {
			uc_close(fd);
			fd = -1;
		}
	}

	return fd;
}

int
ucsock_client_timeout(char *ipstr, int port, int type, int timeout_ms, char *dev)
{
	int fd, ret, flags;
	int error;
	socklen_t len;
	SA_IN addr;

	fd_set rset, wset;
	uctime_s t;

	char ip[UC_BUF_LEN];
	char netmask[UC_BUF_LEN];

	fd = ucsock_socket(AF_INET, type, 0);
	if (fd <= 0) {
		return ERROR;
	}

	if(dev != NULL && strlen(dev) > 0) {
		if(ucsock_fd_bind_to_device(fd, dev) < 0) {
			uc_close(fd);
			uc_err("creat client to[%s:%d] bind device error\n", ipstr, port);
			return ERROR;
		}
	}

	if(type == SOCK_DGRAM && dev != NULL) {
		ucnet_if_get_net_addr(dev, ip, netmask);

		memset(&addr, 0, sizeof (SA_IN));
		addr.sin_family = AF_INET;
		addr.sin_port = htons(0);
		addr.sin_addr.s_addr = inet_addr(ip);

		if (ucsock_bind(fd, &addr) != 0) {
			uc_err("UDP client bind dev[%s] error !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n", dev);
		}
		return fd;
	}

	memset(&addr, 0, sizeof (SA_IN));
	addr.sin_family = AF_INET;
	addr.sin_port = htons(port);
	addr.sin_addr.s_addr = inet_addr(ipstr);

	flags = fcntl(fd, F_GETFL);
	fcntl(fd, F_SETFL, flags | O_NONBLOCK);

	ret = ucsock_connect(fd, (SA *) &addr, sizeof (addr));
	if (ret < 0) {
		if (errno != EINPROGRESS) {
			goto failed_connect;
		}

		while (1) {
			FD_ZERO(&rset);
			FD_SET(fd, &rset);
			FD_ZERO(&wset);
			FD_SET(fd, &wset);

			t.tv_sec = timeout_ms / 1000;
			t.tv_usec = (timeout_ms % 1000) * 1000;

			ret = select(fd + 1, &rset, &wset, NULL, &t);
			if (ret < 0 && errno == EINTR){
				continue;
			}
			if (ret <= 0) {
				goto failed_connect;
			}
			break;
		}

		if ((!FD_ISSET(fd, &rset)) && (!FD_ISSET(fd, &wset))) {
			goto failed_connect;
		}

		error = 0;
		len = sizeof (error);
		ret = getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len);
		if (ret < 0) {
			goto failed_connect;
		}

		if (error) {
			goto failed_connect;
		}
	}

	fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
	return fd;

failed_connect:
	fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
	uc_close(fd);
	return ERROR;
}

int
ucsock_server_unix(char *sun_path, int type)
{
	int fd = 0;
	int ret = 0;
	int on = 0;
	SA_UN servaddr;

	if (sun_path == NULL) {
		uc_err("ucsock_server_unix sun_path NULL\n");
		return ERROR;
	}
	fd = ucsock_socket(AF_LOCAL, type, 0);
	if (fd <= 0) {
		uc_err("socket(%s)\n", sun_path);
		return ERROR;
	}

	on = 1;
	ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on));
	if (ret != OK) {
		close(fd);
		uc_err("setsockopt(%s)\n", sun_path);
		return ERROR;
	}

	remove(sun_path);

	memset(&servaddr, 0, sizeof (servaddr));
	servaddr.sun_family = AF_LOCAL;
	uc_strncpy(servaddr.sun_path, sun_path, sizeof(servaddr.sun_path));
	ret = bind(fd, (SA *) &servaddr, sizeof (servaddr));
	if (ret != OK) {
		close(fd);
		uc_err("bind(%s)\n", sun_path);
		return ERROR;
	}

	chmod(sun_path, 0777);

	if (type == SOCK_STREAM) {
		ret = listen(fd, 256);
		if (ret != OK) {
			close(fd);
			uc_err("listen(%s)\n", sun_path);
			return ERROR;
		}
	}

	return fd;
}

int
ucsock_client_unix(char *sun_path, int type)
{
	int fd = 0;
	int ret = 0;
	SA_UN servaddr;

	if (sun_path == NULL) {
		uc_err("ucsock_client_unix sun_path NULL\n");
		return ERROR;
	}

	fd = ucsock_socket(AF_LOCAL, type, 0);
	if (fd <= 0) {
		//uc_err("socket path[%s] [%d:%s]\n", sun_path, errno, strerror(errno));
		return ERROR;
	}

	memset(&servaddr, 0, sizeof (servaddr));
	servaddr.sun_family = AF_LOCAL;
	uc_strncpy(servaddr.sun_path, sun_path, sizeof(servaddr.sun_path));
	ret = connect(fd, (SA *) &servaddr, sizeof (servaddr));
	if (ret < 0) {
		close(fd);
		return ERROR;
	}

	return fd;
}

int
ucsock_fd_recv_timeout(int fd, int timeout_ms)
{
	uctime_s tv;

	tv.tv_sec = timeout_ms / 1000;
	tv.tv_usec = (timeout_ms % 1000) * 1000;
	return setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (void*) &tv, sizeof(tv));
}

int
ucsock_fd_send_timeout(int fd, int timeout_ms)
{
	uctime_s tv;

	tv.tv_sec = timeout_ms / 1000;
	tv.tv_usec = (timeout_ms % 1000) * 1000;
	return setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (void*) &tv, sizeof(tv));
}

int
ucsock_fd_set_nodelay(int fd)
{
    int flag = 1;

    return setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(flag));
}

int
ucsock_fd_set_nonblock(int fd)
{
	int flags = 0;

	flags = fcntl(fd, F_GETFL);
	if (flags < 0) {
		uc_err("get flag error [errno:%d:%s]\n", errno, strerror(errno));
		return ERROR;
	}
	if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) {
		uc_err("set nonblock error [errno:%d:%s]\n", errno, strerror(errno));
		return ERROR;
	}

	return OK;
}

int
ucsock_fd_set_block(int fd)
{
	int flags = 0;

	flags = fcntl(fd, F_GETFL);
	if (flags < 0) {
		uc_err("get flag error [errno:%d:%s]\n", errno, strerror(errno));
		return ERROR;
	}
      if (fcntl(fd, F_SETFL, flags &~ O_NONBLOCK) < 0) {
		uc_err("set block error [errno:%d:%s]\n", errno, strerror(errno));
		return ERROR;
	}

	return OK;
}

int
ucsock_fd_is_nonblock(int fd)
{
	int flags = 0;
	flags = fcntl(fd, F_GETFL, 0);
	if(flags & O_NONBLOCK) {
		return 1;
	} else {
		return 0;
	}
}

int
ucsock_fd_set_sendbuf(int fd, int buf_size)
{
	int sndbuf1 = 0;
	int sndbuf2 = 0;
	socklen_t optlen = sizeof(sndbuf1);
	int ret = 0;

	getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sndbuf1, &optlen);

	ret = setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (char *)&buf_size, sizeof(buf_size));

	getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sndbuf2, &optlen);

	//uc_info("fd[%d] change sendbuf [%d][%d -> %d]\n", fd, buf_size, sndbuf1, sndbuf2);

	return ret;
}

int
ucsock_fd_set_recvbuf(int fd, int buf_size)
{
    return setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char *)&buf_size, sizeof(buf_size));
}

int
ucsock_fd_bind_to_device(int fd, char *ifname)
{
    struct ifreq ifr;

    memset(&ifr, 0, sizeof(struct ifreq));
    strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
    return setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, (char *)&ifr, sizeof(ifr));
}

int
ucsock_fd_get_info(int fd, char *ipstr, int *port)
{
	int addrlen = 0;
	SA_IN addr;

	addrlen = sizeof(SA_IN);
	getpeername(fd, (SA *)(&addr), (socklen_t *)&addrlen);

	ucsock_inet_addr_ntoa_r(addr.sin_addr, ipstr);
	*port = ntohs(addr.sin_port);

	return OK;
}

int
ucsock_fd_set_linger(int fd, int on_off, int timeout_s)
{
	struct linger linger_data;
	int ret = 0;

	memset(&linger_data, 0, sizeof(linger_data));
	linger_data.l_onoff = on_off;
	linger_data.l_linger = timeout_s;

	ret = setsockopt(fd, SOL_SOCKET, SO_LINGER, (const char *)&linger_data, sizeof(linger_data));

	uc_info("fd[%d] set linger[%d-%d] ret[%d]\n", fd, on_off, timeout_s, ret);

	return ret;
}

#ifdef __cplusplus
}
#endif
